import 'dart:convert';
import 'dart:io';

import 'package:logger/logger.dart';
import 'package:smart_devices/env_config.dart';
import 'package:smart_devices/extension/date.dart';

import 'file_path.dart';

class LogUtils {
  static void writeFromGetx(String text, {bool isError = false}) {
    Future.microtask(
        () => isError ? e('from GetX: $text') : i('from GetX: $text'));
  }

  static final LogPrinter _printer = LogPrinter();

  static void v(dynamic message) {
    _printer.v(message);
  }

  static void d(dynamic message) {
    _printer.d(message);
  }

  static void i(dynamic message) {
    _printer.i(message);
  }

  static void w(dynamic message) {
    _printer.w(message);
  }

  static void e(dynamic message, [dynamic error, StackTrace? stackTrace]) {
    _printer.e(message, error, stackTrace);
  }

  static void wtf(dynamic message) {
    _printer.wtf(message);
  }
}

class LogPrinter {
  LogPrinter() {
    initLogFileOut();
  }

  Logger _logger = Logger(
      filter: ProductionFilter(),
      printer: PrefixPrinter(PrettyPrinter(
          methodCount: 3, dateTimeFormat: DateTimeFormat.dateAndTime)),
      level: EnvConfig.isRelease ? Level.info : Level.trace);

  Future<void> initLogFileOut() async {
    String todayFile = '${DateTime.now().ymd()}.log';
    String? filePath = await FilePathUtils.getLogFilePath(todayFile);
    if (filePath != null && filePath.isNotEmpty) {
      var file = File(filePath);
      if (!file.existsSync()) {
        file.createSync();
      }
      _logger = Logger(
          filter: ProductionFilter(),
          output: MultiOutput([ConsoleOutput(), FileOutput(file: file)]),
          printer: PrefixPrinter(PrettyPrinter(
              methodCount: 3, dateTimeFormat: DateTimeFormat.dateAndTime)),
          level: EnvConfig.isRelease ? Level.info : Level.trace);
    }
  }

  void v(dynamic message) {
    _logger.t(message);
  }

  void d(dynamic message) {
    _logger.d(message);
  }

  void i(dynamic message) {
    _logger.i(message);
  }

  void w(dynamic message) {
    _logger.w(message);
  }

  void e(dynamic message, [dynamic error, StackTrace? stackTrace]) {
    _logger.e(message, error: error, stackTrace: stackTrace);
  }

  void wtf(dynamic message) {
    _logger.f(message);
  }
}

/// Writes the log output to a file.
class FileOutput extends LogOutput {
  final File file;
  final bool overrideExisting;
  final Encoding encoding;
  IOSink? _sink;

  FileOutput({
    required this.file,
    this.overrideExisting = false,
    this.encoding = utf8,
  });

  @override
  Future<void> init() async {
    _sink = file.openWrite(
      mode: overrideExisting ? FileMode.writeOnly : FileMode.writeOnlyAppend,
      encoding: encoding,
    );
  }

  @override
  void output(OutputEvent event) {
    _sink?.writeAll(event.lines, '\n');
    _sink?.writeln();
  }

  @override
  Future<void> destroy() async {
    await _sink?.flush();
    await _sink?.close();
  }
}
